use crate::gen_title;

pub fn ch2_14_1() {
    gen_title("ch2_14_1", 18);

    enum Direction {
        East,
        West,
        North,
        South,
    }

    let dire = Direction::South;

    match dire {
        Direction::East => println!("East"),
        Direction::North | Direction::South => {
            println!("South or North");
        }
        _ => println!("West"),
    };
}

pub fn ch2_14_2() {
    gen_title("ch2_14_2", 18);

    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter,
    }

    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => {
                println!("Lucky penny!");
                1
            }
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }

    let coin = Coin::Nickel;

    let result = value_in_cents(coin);
    println!("result is {}", result);
}

pub fn ch2_14_3() {
    gen_title("ch2_14_3", 18);

    #[derive(Debug)]
    enum IpAddr {
        Ipv4,
        Ipv6,
    }

    let ip1 = IpAddr::Ipv4;
    let ip_str = match ip1 {
        IpAddr::Ipv4 => "127.0.0.1",
        _ => "::1",
    };

    print!("{}", ip_str);
}

pub fn ch2_14_4() {
    gen_title("ch2_14_4", 18);

    #[derive(Debug)]
    enum UsState {
        Alabama,
        Alaska,
    }

    #[derive(Debug)]
    enum Coin {
        Penny,
        Nickel,
        Dime,
        Quarter(UsState),
    }

    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => 1,
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter(state) => {
                println!("State quarter from {:?}", state);
                25
            }
        }
    }

    let coin = Coin::Quarter(UsState::Alaska);
    let result = value_in_cents(coin);
    println!("result is {}", result);
}

pub fn ch2_14_5() {
    gen_title("ch2_14_5", 18);

    enum Action {
        Say(String),
        MoveTo(i32, i32),
        ChangeColorRGB(u16, u16, u16),
    }

    let actions = [
        Action::Say("Hello Rust".to_string()),
        Action::MoveTo(1, 2),
        Action::ChangeColorRGB(255, 255, 0),
    ];

    for action in actions {
        match action {
            Action::Say(s) => {
                println!("{}", s);
            }
            Action::MoveTo(x, y) => {
                println!("point from (0, 0) move to ({}, {})", x, y);
            }
            Action::ChangeColorRGB(r, g, _) => {
                println!(
                    "change color into '(r:{}, g:{}, b:0), 'b' has been ignored",
                    r, g
                );
            }
        }
    }
}

pub fn ch2_14_6() {
    gen_title("ch2_14_6", 18);

    let some_u8_value = 5u8;

    match some_u8_value {
        1 => println!("one"),
        3 => println!("three"),
        5 => println!("five"),
        7 => println!("seven"),
        _ => (),
    }
}

pub fn ch2_14_7() {
    gen_title("ch2_14_7", 18);

    #[derive(Debug)]
    enum Direction {
        East,
        West,
        North,
        South,
    }

    let dire = Direction::South;

    match dire {
        Direction::East => println!("East"),
        other => println!("other direction: {:?}", other),
    };
}

pub fn ch2_14_8() {
    gen_title("ch2_14_8", 18);

    let v = Some(3u8);

    match v {
        Some(3) => println!("three"),
        _ => (),
    }

    let v = Some(5);

    if let Some(n) = v {
        println!("five, {}", n)
    }
}

pub fn ch2_14_9() {
    gen_title("ch2_14_9", 18);

    #[derive(Debug)]
    enum MyEnum {
        Foo,
        Bar,
    }

    let v = vec![MyEnum::Foo, MyEnum::Bar, MyEnum::Foo];

    let result: Vec<&MyEnum> = v.iter().filter(|x| matches!(x, MyEnum::Foo)).collect();
    println!("result is {:?}", result);

    let foo = 'f';
    assert!(matches!(foo,'A'..='Z'|'a'..='z'));

    let bar = Some(4);
    assert!(matches!(bar,Some(x) if x>2));
}

pub fn ch2_14_10() {
    gen_title("ch2_14_10", 18);

    let age = Some(30);
    println!("在匹配前, age 是{:?}", age);
    if let Some(age) = age {
        println!("匹配出来的 age 是{}", age);
    }

    println!("在匹配后, age 是{:?}", age);
}

pub fn ch2_14_11() {
    gen_title("ch2_14_11", 18);

    let age = Some(30);
    println!("在匹配前, age 是{:?}", age);
    match age {
        Some(age) => println!("匹配出来的 age 是{}", age),
        _ => (),
    }
    println!("在匹配后, age 是{:?}", age);
}

pub fn ch2_14_pra_1() {
    gen_title("ch2_14_pra_1", 18);

    enum Direction {
        East,
        West,
        North,
        South,
    }

    let dire = Direction::South;
    match dire {
        Direction::East => println!("East"),
        Direction::South | Direction::North => println!("South or North"),
        _ => println!("West"),
    };
}

pub fn ch2_14_pra_2() {
    gen_title("ch2_14_pra_2", 18);

    let boolean = true;

    let binary = match boolean {
        true => 1,
        false => 0,
    };

    assert_eq!(binary, 1);
    println!("binary is {}", binary);
}

pub fn ch2_14_pra_3() {
    gen_title("ch2_14_pra_3", 18);
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msgs = [
        Message::Quit,
        Message::Move { x: 1, y: 3 },
        Message::ChangeColor(255, 255, 0),
    ];

    for msg in msgs {
        show_message(msg)
    }

    fn show_message(msg: Message) {
        match msg {
            Message::Move { x: a, y: b } => {
                println!("move to ({}, {})", a, b);
            }
            Message::ChangeColor(_, g, b) => {
                println!("change color into '(r:255, g:{}, b:{})'", g, b);
            }
            Message::Quit => println!("no data in these variants"),
            _ => (),
        }
    }
}

pub fn ch2_14_pra_4() {
    gen_title("ch2_14_pra_4", 18);

    let alphabets = ['a', 'E', 'Z', '0', 'x', '9', 'Y'];

    for ab in alphabets {
        assert!(matches!(ab,'A'..='Z'|'a'..='z'|'0'..='9'))
    }
    println!("all alphabets are matched");
}

pub fn ch2_14_pra_5() {
    gen_title("ch2_14_pra_5", 18);

    enum MyEnum {
        Foo,
        Bar,
    }

    let mut count = 0;

    let v = vec![MyEnum::Foo, MyEnum::Bar, MyEnum::Foo];
    for e in v {
        if let MyEnum::Foo = e {
            count += 1;
        }
    }

    println!("count is {}", count);
    assert_eq!(count, 2);
}

pub fn ch2_14_pra_6() {
    gen_title("ch2_14_pra_6", 18);
    let o = Some(7);

    match o {
        Some(i) => {
            println!("This is a really long string and '{:?}'", i);
        }
        _ => {}
    };

    if let Some(i) = o {
        println!("This is a really long string and '{:?}'", i);
    }
}

pub fn ch2_14_pra_7() {
    gen_title("ch2_14_pra_7", 18);

    enum Foo {
        Bar(u8),
    }

    let a = Foo::Bar(1);

    if let Foo::Bar(i) = a {
        println!("foobar 持有的值是: {}", i);
    }
}

pub fn ch2_14_pra_8() {
    gen_title("ch2_14_pra_8", 18);

    enum Foo {
        Bar,
        Baz,
        Qux(u32),
    }

    let a = Foo::Qux(10);

    match a {
        Foo::Bar => {
            println!("match foo::bar");
        }
        Foo::Baz => {
            println!("match foo::baz");
        }
        Foo::Qux(n) => {
            println!("match foo::qux, n is {}", n);
        }
    }
}

pub fn ch2_14_pra_9() {
    gen_title("ch2_14_pra_9", 18);

    let age = Some(30);
    if let Some(age) = age {
        assert_eq!(age, 30);
    }

    match age {
        Some(age) => println!("age is {}", age),
        _ => (),
    }

    println!("age is {:?}", age);
}
